#include <iostream>
#include "basic/basic.h"
#include "thread/blocked_thread.hpp"
#include "thread/auto_thread.hpp"
#include "thread/scoped_thread.hpp"

#include "thread/thread.h"
#include "thread/thread_pool/thread_pool.h"

#include "process/processor.h"

#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>

void testAutoThread(){
	boost::this_thread::sleep(boost::posix_time::seconds(rand() % 5));
	std::cout << "testAutoThread " << time(NULL) << std::endl;
}
void testScopedThread(){
	boost::this_thread::sleep(boost::posix_time::seconds(rand() % 20));
	std::cout << "testScopedThread " << time(NULL) << std::endl;
}
void testBlockedThread(){
	boost::this_thread::sleep(boost::posix_time::seconds(rand() % 10));
	std::cout << "testBlockedThread " << time(NULL) << std::endl;
}
void testThreadPool(){
	boost::this_thread::sleep(boost::posix_time::milliseconds(rand() % 100));
	std::cout << "testThreadPool th:" << boost::this_thread::get_id() << std::endl;
}
void testAsyncTaskFun(int num){
	boost::this_thread::sleep(boost::posix_time::milliseconds(rand() % 100));
	std::cout << "testAsyncTaskFun num:" << num << ",th:" << boost::this_thread::get_id() << std::endl;
}
void testChan(eyas::process::chan<int>& ch){
	std::cout << "send num:1,th:" << boost::this_thread::get_id() << std::endl;
	ch << 1;
	boost::this_thread::sleep(boost::posix_time::seconds(1));
	std::cout << "send num:2,th:" << boost::this_thread::get_id() << std::endl;
	ch << 2;
	boost::this_thread::sleep(boost::posix_time::seconds(3));
	std::cout << "send num:3,th:" << boost::this_thread::get_id() << std::endl;
	ch << 3;
}
class testAsyncTask{
public:
	void test(int num){
		boost::this_thread::sleep(boost::posix_time::milliseconds(rand() % 100));
		std::cout << "testAsyncTask::test num:" << num << ",th:" << boost::this_thread::get_id() << std::endl;
	}
};
void testTimer(){
	std::cout << "testTimer " << boost::this_thread::get_id() << std::endl;
}

class testTimerCls{
public:
	void test(){
		std::cout << "testTimerCls::test " << boost::this_thread::get_id() << std::endl;
	}
};


///////////////////////////
class Base{
public:
	Base():val_(0){
		//std::cout << "Deliver::Base" << std::endl;
	}
	virtual ~Base(){
		//std::cout << "Deliver::~Base" << std::endl;
	}

	virtual void print(){
		//std::cout << "Base::print" << std::endl;
	};
private:
	int val_;
};
class Deliver : public Base{
public:
	Deliver(){
		//std::cout << "Deliver::Deliver" << std::endl;
	}
	virtual ~Deliver(){
		//std::cout << "Deliver::~Deliver" << std::endl;
	}

	virtual void print(){
		//std::cout << "Deliver::print" << std::endl;
	};
};
class DeliverEx : public Base, public eyas::gc::enable_memory_pool<DeliverEx>{
public:
	DeliverEx(){
		//std::cout << "Deliver::Deliver" << std::endl;
	}
	virtual ~DeliverEx(){
		//std::cout << "Deliver::~Deliver" << std::endl;
	}

	virtual void print(){
		//std::cout << "Deliver::print" << std::endl;
	};
};

//////////////////////////

template <typename T>
void test_template(T t){

}

int main() {
	{
		DeliverEx deliver;
		DeliverEx& deliver2 = deliver;
		test_template(deliver2);
	}
	typedef boost::shared_ptr<Base> BasePtr;
	typedef boost::shared_ptr<Deliver> DeliverPtr;
	//{
	//	DeliverPtr dptr = eyas::gc::create_new<Deliver>();
	//	
	//	std::cout << "Enter test release" << std::endl;
	//	getchar();
	//}
	//{
	//	BasePtr bptr;
	//	{
	//		std::cout << "Enter test reuse" << std::endl;
	//		getchar();
	//		DeliverPtr dptr = eyas::gc::create_new<Deliver>();

	//		bptr = dptr;
	//	}
	//	std::cout << "Enter test reuse release" << std::endl;
	//	getchar();
	//}
	clock_t clk = 0;
	clock_t clk2 = 0;
	void* mem = 0;

	eyas::gc::init();
	do{
		clk = ::clock();
		for(int i=0; i<500000; i++){
			DeliverPtr dptr = eyas::gc::create_new<Deliver>();
			DeliverPtr dptr2 = eyas::gc::create_new<Deliver>();
			DeliverPtr dptr3 = eyas::gc::create_new<Deliver>();

			dptr->print();
			dptr2->print();
			dptr3->print();
		}
		clk2 = ::clock();
		std::cout << "eyas::gc::create_new shared_ptr waste time: " << (clk2-clk) << std::endl;
		//getchar();
		clk = ::clock();
		for(int i=0; i<500000; i++){
			mem = eyas::gc::static_memory_pool<sizeof(Deliver)>::instance()->allocate();
			DeliverPtr dptr(new (mem) Deliver(), eyas::gc::deleter_t<Deliver>());
			mem = eyas::gc::static_memory_pool<sizeof(Deliver)>::instance()->allocate();
			DeliverPtr dptr2(new (mem) Deliver(), eyas::gc::deleter_t<Deliver>());
			mem = eyas::gc::static_memory_pool<sizeof(Deliver)>::instance()->allocate();
			DeliverPtr dptr3(new (mem) Deliver(), eyas::gc::deleter_t<Deliver>());

			
			dptr->print();
			dptr2->print();
			dptr3->print();
		}
		clk2 = ::clock();
		std::cout << "eyas::gc::deleter_t shared_ptr waste time: " << (clk2-clk) << std::endl;
		
		//getchar();
		clk = ::clock();
		for(int i=0; i<500000; i++){
			DeliverPtr dptr = boost::make_shared<Deliver>();
			DeliverPtr dptr2 = boost::make_shared<Deliver>();
			DeliverPtr dptr3 = boost::make_shared<Deliver>();

			
			dptr->print();
			dptr2->print();
			dptr3->print();
		}
		clk2 = ::clock();
		std::cout << "boost::make_shared shared_ptr waste time: " << (clk2-clk) << std::endl;
		//getchar();

		
		clk = ::clock();
		for(int i=0; i<500000; i++){
			// 可能有内存泄漏风险
			mem = eyas::gc::static_memory_pool<sizeof(DeliverEx)>::instance()->allocate();
			DeliverEx* dptr = new (mem) DeliverEx();
			mem = eyas::gc::static_memory_pool<sizeof(DeliverEx)>::instance()->allocate();
			DeliverEx* dptr2 = new (mem) DeliverEx();
			mem = eyas::gc::static_memory_pool<sizeof(DeliverEx)>::instance()->allocate();
			DeliverEx* dptr3 = new (mem) DeliverEx();

			dptr->print();
			dptr2->print();
			dptr3->print();

			dptr->~DeliverEx();
			dptr2->~DeliverEx();
			dptr3->~DeliverEx();
			eyas::gc::static_memory_pool<sizeof(DeliverEx)>::instance()->deallocate(dptr);
			eyas::gc::static_memory_pool<sizeof(DeliverEx)>::instance()->deallocate(dptr2);
			eyas::gc::static_memory_pool<sizeof(DeliverEx)>::instance()->deallocate(dptr3);
		}
		clk2 = ::clock();
		std::cout << "eyas::gc::static_memory_pool raw waste time: " << (clk2-clk) << std::endl;
		clk = ::clock();
		for(int i=0; i<500000; i++){
			DeliverEx* dptr = new DeliverEx();
			DeliverEx* dptr2 = new DeliverEx();
			DeliverEx* dptr3 = new DeliverEx();

			dptr->print();
			dptr2->print();
			dptr3->print();


			delete dptr;
			delete dptr2;
			delete dptr3;
		}
		clk2 = ::clock();
		std::cout << "eyas::gc::static_memory_pool raw new waste time: " << (clk2-clk) << std::endl;
		clk = ::clock();
		for(int i=0; i<500000; i++){
			Deliver* dptr = new Deliver();
			Deliver* dptr2 = new Deliver();
			Deliver* dptr3 = new Deliver();

			dptr->print();
			dptr2->print();
			dptr3->print();


			delete dptr;
			delete dptr2;
			delete dptr3;
		}
		clk2 = ::clock();
		std::cout << "raw new waste time: " << (clk2-clk) << std::endl;


		{
			DeliverPtr dptr = eyas::gc::create_new<Deliver>();
			DeliverPtr dptr2 = eyas::gc::create_new<Deliver>();
			DeliverPtr dptr3 = eyas::gc::create_new<Deliver>();
			clk = ::clock();
			for(int i=0; i<500000; i++){
				dptr->print();
				dptr2->print();
				dptr3->print();
			}
			clk2 = ::clock();
		}
		std::cout << "shared_ptr call waste time: " << (clk2-clk) << std::endl;
		{
			Deliver* dptr = new Deliver();
			Deliver* dptr2 = new Deliver();
			Deliver* dptr3 = new Deliver();
			clk = ::clock();
			for(int i=0; i<500000; i++){
				dptr->print();
				dptr2->print();
				dptr3->print();
			}
			clk2 = ::clock();
			delete dptr;
			delete dptr2;
			delete dptr3;
		}
		std::cout << "raw call waste time: " << (clk2-clk) << std::endl;
		getchar();
	}while(false);
	{	// 测试线程
		std::cout << "Enter test thread" << std::endl;
		getchar();

		eyas::thread::blocked_thread blockedThread(&testBlockedThread);
		eyas::thread::auto_thread autoThread(&testAutoThread);
		eyas::thread::scoped_thread scopedThread(&testScopedThread);
	}

	{	// 测试任务队列
		eyas::thread::init();
		eyas::thread::thread_pool threadPool;
		for(int i=0; i<100; i++){
			//threadPool.schedule(&testThreadPool);
			threadPool.schedule([i](){
				boost::this_thread::sleep(boost::posix_time::milliseconds(rand() % 100));
				std::cout << "test thread pool th:" << boost::this_thread::get_id() << std::endl;
				if(i == 99){
					std::cout << "press Enter to the next test" << std::endl;
				}
			});
		}
		getchar();
	}
	{	// 测试并发编程
		eyas::process::init();
		// 测试异步任务
		std::cout << "Enter test async task" << std::endl;
		getchar();
		for(int i=0; i<100; i++){
			eyas::process::fly(&testThreadPool);
			eyas::process::fly(&testAsyncTaskFun, i);
			eyas::process::fly(&testAsyncTask::test, boost::shared_ptr<testAsyncTask>(new testAsyncTask()), i);
			eyas::process::fly([i](){
				std::cout << "async task lambdas num:" << i << std::endl;
			});
			//boost::bind(testAsyncTask::test, boost::shared_ptr<testAsyncTask>(new testAsyncTask()), i);
		}
		getchar();
		// 测试任务序列
		std::cout << "Enter test sequential task" << std::endl;
		getchar();
		{
			eyas::process::sequential_task_ptr seqTaskPtr = eyas::process::create_sequential_task();
			for(int i=0; i<100; i++){
				eyas::process::fly(seqTaskPtr, &testThreadPool);
				eyas::process::fly(seqTaskPtr, &testAsyncTaskFun, i);
				eyas::process::fly(seqTaskPtr, &testAsyncTask::test, boost::shared_ptr<testAsyncTask>(new testAsyncTask()), i);
			
				eyas::process::fly(seqTaskPtr, [i](){
					std::cout << "sequential task lambdas num:" << i << std::endl;
				});
			}
		}
		getchar();
		// 测试互斥通道
		std::cout << "Enter test mutex chan" << std::endl;
		getchar();
		eyas::process::chan<int> ch = eyas::process::create_chan<int>();
		eyas::process::fly(&testChan, ch);
		int num = 0;
		for(int i=0; i<3; i++){
			if(ch >> num){
				std::cout << "received num:" << num << ",th:" << boost::this_thread::get_id() << std::endl;
			}else{
				break;
			}
		}
		std::cout << "mutex chan test completed" << std::endl;
		getchar();
		std::cout << "Enter test the timer, the second Enter cancel the timer." << std::endl;
		getchar();
		eyas::process::timer_ptr timerPtr1 = eyas::process::fly_timer(1000, 1000, &testTimer);
		eyas::process::timer_ptr timerPtr2 = eyas::process::fly_timer(1000, 1000, &testTimerCls::test, boost::shared_ptr<testTimerCls>(new testTimerCls()));
		getchar();
		timerPtr1->cancel();
		timerPtr2->cancel();
		std::cout << "timer is canceled." << std::endl;
	}
	std::cout << "Enter exit the test." << std::endl;
	getchar();
	return 0;
}
